package com.example.demo.Proxy;

import com.example.demo.Dao.PersonDao;
import com.example.demo.Dao.PersonDaoImpl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @Author : 叶荻风
 * @create : 2024/5/22 20:02
 */
public class TestJdkProxy {
    public static void main(String[] args) {

        //原始对象
        PersonDao personDao = new PersonDaoImpl();

        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(proxy.getClass().getName() + "  adadadas");
                Object invoke = method.invoke(personDao, args);
                System.out.println(proxy.getClass().getName() + "  adadadas");
                return invoke;
            }
        };
        PersonDao o = (PersonDao) Proxy.newProxyInstance(TestJdkProxy.class.getClassLoader(),
                personDao.getClass().getInterfaces(),
                invocationHandler);
        o.queryByName("dasdd");

    }

//    选择类加载器时，确实有一些重要的考虑因素，尤其是当涉及到代理对象的创建时。你遇到的问题com.example.demo.Dao.PersonDao referenced from a method is not
//    visible from class loader，提示了代理对象的类加载器无法访问到PersonDao接口。这很可能是因为你使用了Object.class.getClassLoader()
//    作为代理对象的类加载器，但这并不是一个理想的实践，原因如下：
//
//不恰当的类加载器选择：Object.class.getClassLoader()通常会返回引导类加载器（Bootstrap ClassLoader），它负责加载Java的核心库，如java
// .*包下的类。使用引导类加载器来加载用户自定义的类或接口（如PersonDao）通常是不合适的，因为引导类加载器并不负责加载这些内容。这意味着，通过引导类加载器创建的代理对象将无法看到由应用程序类加载器加载的PersonDao接口。
//
//类加载器隔离原则：Java的类加载机制遵循双亲委派模型，每个类加载器都有自己的命名空间。使用不同的类加载器加载同一个类的实例，即使类名完全相同，这两个类也被视为不同类。因此，由Object.class.getClassLoader
// ()创建的代理对象实际上处于不同的类加载上下文中，无法访问到由应用程序类加载器加载的接口。
//
//正确的做法是使用能够访问到PersonDao接口的类加载器来创建代理对象。一般来说，你应该使用加载PersonDao接口的那个类加载器，这通常是应用程序类加载器（Application Class
// Loader），它负责加载用户类路径（classpath）上的类。
}
